package org.zz.gmhelper;


import javax.crypto.Cipher;
import java.nio.charset.Charset;
import java.security.*;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Arrays;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;

import static java.nio.charset.StandardCharsets.UTF_8;

/**
 * RSA签名验签类
 */
public class RSAUtils {

    private static final String SIGN_ALGORITHMS = "SHA256withRSA";
    private static final int MAX_ENCRYPT_BLOCK_SIZE = 117; // 对于2048位密钥
    private static final int MAX_DECRYPT_BLOCK_SIZE = 256; // 对于2048位密钥

    private static String sign(String content, String privateKey, Charset encode) throws Exception {
        PKCS8EncodedKeySpec priPKCS8 = new PKCS8EncodedKeySpec(Base64.getDecoder().decode(privateKey));
        KeyFactory keyf = KeyFactory.getInstance("RSA");
        PrivateKey priKey = keyf.generatePrivate(priPKCS8);

        Signature signature = Signature.getInstance(SIGN_ALGORITHMS);
        signature.initSign(priKey);
        signature.update(content.getBytes(encode));
        return Base64.getEncoder().encodeToString(signature.sign());
    }

    //加签
    public static String sign(String content, String privateKey) throws Exception {
        return sign(content, privateKey, UTF_8);
    }

    private static boolean verify(String content, String sign, String publicKey, Charset encode) throws Exception {
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        byte[] encodedKey = Base64.getDecoder().decode(publicKey);
        PublicKey pubKey = keyFactory.generatePublic(new X509EncodedKeySpec(encodedKey));

        Signature signature = Signature.getInstance(SIGN_ALGORITHMS);
        signature.initVerify(pubKey);
        signature.update(content.getBytes(encode));
        return signature.verify(Base64.getDecoder().decode(sign));
    }


    //验签
    public static boolean verify(String content, String sign, String publicKey) throws Exception {
        return verify(content, sign, publicKey, UTF_8);
    }

    //加密
    public static String encrypt(String data, String publicKey) throws Exception {
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        byte[] encodedKey = Base64.getDecoder().decode(publicKey);
        PublicKey pubKey = keyFactory.generatePublic(new X509EncodedKeySpec(encodedKey));

        Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
        cipher.init(Cipher.ENCRYPT_MODE, pubKey);

        // 处理大块数据加密
        byte[] plainBytes = data.getBytes(UTF_8);
        StringBuilder encryptedText = new StringBuilder();
        for (int i = 0; i < plainBytes.length; i += MAX_ENCRYPT_BLOCK_SIZE) {
            byte[] block = Arrays.copyOfRange(plainBytes, i, Math.min(i + MAX_ENCRYPT_BLOCK_SIZE, plainBytes.length));
            byte[] encryptedBlock = cipher.doFinal(block);
            encryptedText.append(Base64.getEncoder().encodeToString(encryptedBlock));
        }
        return encryptedText.toString();
    }


    //解密
    public static String decrypt(String data, String privateKey) throws Exception {
        PKCS8EncodedKeySpec priPKCS8 = new PKCS8EncodedKeySpec(Base64.getDecoder().decode(privateKey));
        KeyFactory keyf = KeyFactory.getInstance("RSA");
        PrivateKey priKey = keyf.generatePrivate(priPKCS8);

        Cipher decriptCipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
        decriptCipher.init(Cipher.DECRYPT_MODE, priKey);

        // 处理大块数据解密
        byte[] encryptedBytes = Base64.getDecoder().decode(data);
        StringBuilder decryptedText = new StringBuilder();
        for (int i = 0; i < encryptedBytes.length; i += MAX_DECRYPT_BLOCK_SIZE) {
            byte[] block = Arrays.copyOfRange(encryptedBytes, i, Math.min(i + MAX_DECRYPT_BLOCK_SIZE, encryptedBytes.length));
            byte[] decryptedBlock = decriptCipher.doFinal(block);
            decryptedText.append(new String(decryptedBlock, UTF_8));
        }
        return decryptedText.toString();
    }

    public static KeyPair generateRsaKeyPair() throws NoSuchAlgorithmException {
        KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
        keyGen.initialize(2048); // 选择密钥长度
        return keyGen.generateKeyPair();
    }

    public static String getPublicKey( PublicKey publicKey)  {
        byte[] publicKeyBytes = publicKey.getEncoded();
        return Base64.getEncoder().encodeToString(publicKeyBytes);
    }

    public static String getPrivateKey(PrivateKey privateKey)  {
        byte[] privateKeyBytes = privateKey.getEncoded();
        return Base64.getEncoder().encodeToString(privateKeyBytes);
    }

    public static void main(String[] args) {
        try {
//            Security.addProvider(new BouncyCastleProvider());

            // 生成 RSA 密钥对
            KeyPair keyPair = generateRsaKeyPair();


            String publicKeyPem = getPublicKey(keyPair.getPublic());
            String privateKeyPem = getPrivateKey(keyPair.getPrivate());

            Map<String, String> map = new HashMap<>();
            map.put("code", "1234");
            map.put("captchaExpiration", "5");
            String data = map.toString();
            System.out.println("加密前数据:" +data);
            String data1= encrypt(data, publicKeyPem);

            String sign= sign(data, privateKeyPem);
            System.out.println("获取签名:" +sign);
            System.out.println("公钥加密结果:" +data1 );

            System.out.println("私钥解密结果:" + decrypt(data1, privateKeyPem));
            System.out.println("验签结果:" +verify(decrypt(data1, privateKeyPem),sign, publicKeyPem));

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
